/**
 * MainPanel
 *
 * @author pquiring
 *
 * Date : Feb 8, 2012
 *
 */

import javax.swing.*;
import javax.swing.filechooser.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.font.*;
import java.io.*;
import java.util.*;

import javaforce.*;
import javaforce.gl.*;

public class MainPanel extends javax.swing.JPanel implements MouseListener, MouseMotionListener, KeyListener, KeyEventDispatcher, ActionListener {

  public static String version = "0.25";

  /**
   * Creates new form PaintPanel
   */
  public MainPanel(JFrame frame, JApplet applet) {
    try {
      this.frame = frame;
      PaintCanvas.mainPanel = this;
      Border.panel = this;
      initComponents();
      setLayout(new PanelLayout());  //can't make netbeans work properly
      addTab("untitled");
      updateClr(foreColor, foreClr);
      updateClr(backColor, backClr);
      selBox.setSelected(true);
      javax.swing.Timer timer = new javax.swing.Timer(250, this);
      timer.start();
      KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
      selBox.doClick();
      currentPath = JF.getUserPath() + "/Pictures";
      thresholdSliderStateChanged(null);
      alphaSliderStateChanged(null);
      paintMode.setMaximumRowCount(paintMode.getItemCount());  //default is 8
      rotateImg = new JFImage();
      rotateImg.load(this.getClass().getResourceAsStream("rotate.png"));
      pixel = new JFImage(1,1);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    group = new javax.swing.ButtonGroup();
    toolbar1 = new javax.swing.JToolBar();
    selBox = new javax.swing.JToggleButton();
    fill = new javax.swing.JToggleButton();
    pickColor = new javax.swing.JToggleButton();
    pencil = new javax.swing.JToggleButton();
    text = new javax.swing.JToggleButton();
    curve = new javax.swing.JToggleButton();
    line = new javax.swing.JToggleButton();
    box = new javax.swing.JToggleButton();
    circle = new javax.swing.JToggleButton();
    sub = new javax.swing.JToggleButton();
    jLabel3 = new javax.swing.JLabel();
    rotateCW = new javax.swing.JButton();
    rotateCCW = new javax.swing.JButton();
    flipVert = new javax.swing.JButton();
    flipHorz = new javax.swing.JButton();
    scaleSize = new javax.swing.JButton();
    jLabel4 = new javax.swing.JLabel();
    fillMode = new javax.swing.JToggleButton();
    fillAlpha = new javax.swing.JToggleButton();
    fillEdge = new javax.swing.JToggleButton();
    round = new javax.swing.JToggleButton();
    selkeyclr = new javax.swing.JToggleButton();
    selFillAlpha = new javax.swing.JToggleButton();
    jLabel5 = new javax.swing.JLabel();
    selectFont = new javax.swing.JButton();
    changeSize = new javax.swing.JButton();
    crop = new javax.swing.JButton();
    backswap = new javax.swing.JButton();
    toolbar2 = new javax.swing.JToolBar();
    foreColor = new javax.swing.JButton();
    swap = new javax.swing.JButton();
    backColor = new javax.swing.JButton();
    width = new javax.swing.JComboBox();
    paintMode = new javax.swing.JComboBox();
    colorLayer = new javax.swing.JComboBox();
    layersButton = new javax.swing.JButton();
    toolbar3 = new javax.swing.JToolBar();
    jLabel1 = new javax.swing.JLabel();
    threshold = new javax.swing.JLabel();
    thresholdSlider = new javax.swing.JSlider();
    jLabel2 = new javax.swing.JLabel();
    alpha = new javax.swing.JLabel();
    alphaSlider = new javax.swing.JSlider();
    jLabel6 = new javax.swing.JLabel();
    zoom = new javax.swing.JSlider();
    zoomText = new javax.swing.JLabel();
    tabs = new javax.swing.JTabbedPane();
    status = new javax.swing.JTextField();

    toolbar1.setFloatable(false);
    toolbar1.setRollover(true);

    group.add(selBox);
    selBox.setIcon(new javax.swing.ImageIcon(getClass().getResource("/selbox.png"))); // NOI18N
    selBox.setToolTipText("Selection Box");
    selBox.setFocusable(false);
    selBox.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    selBox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    selBox.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        selBoxActionPerformed(evt);
      }
    });
    toolbar1.add(selBox);

    group.add(fill);
    fill.setIcon(new javax.swing.ImageIcon(getClass().getResource("/fill.png"))); // NOI18N
    fill.setToolTipText("Fill (uses threshold)");
    fill.setFocusable(false);
    fill.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    fill.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    fill.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        fillActionPerformed(evt);
      }
    });
    toolbar1.add(fill);

    group.add(pickColor);
    pickColor.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pickcolor.png"))); // NOI18N
    pickColor.setToolTipText("Pick Color");
    pickColor.setFocusable(false);
    pickColor.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    pickColor.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    pickColor.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        pickColorActionPerformed(evt);
      }
    });
    toolbar1.add(pickColor);

    group.add(pencil);
    pencil.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pencil.png"))); // NOI18N
    pencil.setToolTipText("Pencil");
    pencil.setFocusable(false);
    pencil.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    pencil.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    pencil.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        pencilActionPerformed(evt);
      }
    });
    toolbar1.add(pencil);

    group.add(text);
    text.setIcon(new javax.swing.ImageIcon(getClass().getResource("/text.png"))); // NOI18N
    text.setToolTipText("Text");
    text.setFocusable(false);
    text.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    text.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    text.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        textActionPerformed(evt);
      }
    });
    toolbar1.add(text);

    group.add(curve);
    curve.setIcon(new javax.swing.ImageIcon(getClass().getResource("/curve.png"))); // NOI18N
    curve.setToolTipText("Curve");
    curve.setFocusable(false);
    curve.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    curve.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    curve.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        curveActionPerformed(evt);
      }
    });
    toolbar1.add(curve);

    group.add(line);
    line.setIcon(new javax.swing.ImageIcon(getClass().getResource("/line.png"))); // NOI18N
    line.setToolTipText("Line");
    line.setFocusable(false);
    line.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    line.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    line.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        lineActionPerformed(evt);
      }
    });
    toolbar1.add(line);

    group.add(box);
    box.setIcon(new javax.swing.ImageIcon(getClass().getResource("/box.png"))); // NOI18N
    box.setToolTipText("Box");
    box.setFocusable(false);
    box.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    box.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    box.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        boxActionPerformed(evt);
      }
    });
    toolbar1.add(box);

    group.add(circle);
    circle.setIcon(new javax.swing.ImageIcon(getClass().getResource("/circle.png"))); // NOI18N
    circle.setToolTipText("Circle");
    circle.setFocusable(false);
    circle.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    circle.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    circle.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        circleActionPerformed(evt);
      }
    });
    toolbar1.add(circle);

    group.add(sub);
    sub.setIcon(new javax.swing.ImageIcon(getClass().getResource("/sub.png"))); // NOI18N
    sub.setToolTipText("Substitute Box -  Changes backColor to foreColor within drawn Box (uses threshold)");
    sub.setFocusable(false);
    sub.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    sub.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    sub.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        subActionPerformed(evt);
      }
    });
    toolbar1.add(sub);

    jLabel3.setText(":");
    toolbar1.add(jLabel3);

    rotateCW.setIcon(new javax.swing.ImageIcon(getClass().getResource("/rotatecw.png"))); // NOI18N
    rotateCW.setToolTipText("Rotate CW");
    rotateCW.setFocusable(false);
    rotateCW.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    rotateCW.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    rotateCW.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        rotateCWActionPerformed(evt);
      }
    });
    toolbar1.add(rotateCW);

    rotateCCW.setIcon(new javax.swing.ImageIcon(getClass().getResource("/rotateccw.png"))); // NOI18N
    rotateCCW.setToolTipText("Rotate CCW");
    rotateCCW.setFocusable(false);
    rotateCCW.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    rotateCCW.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    rotateCCW.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        rotateCCWActionPerformed(evt);
      }
    });
    toolbar1.add(rotateCCW);

    flipVert.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flipvert.png"))); // NOI18N
    flipVert.setToolTipText("Flip Vertical");
    flipVert.setFocusable(false);
    flipVert.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    flipVert.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    flipVert.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        flipVertActionPerformed(evt);
      }
    });
    toolbar1.add(flipVert);

    flipHorz.setIcon(new javax.swing.ImageIcon(getClass().getResource("/fliphorz.png"))); // NOI18N
    flipHorz.setToolTipText("Fill Horizontal");
    flipHorz.setFocusable(false);
    flipHorz.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    flipHorz.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    flipHorz.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        flipHorzActionPerformed(evt);
      }
    });
    toolbar1.add(flipHorz);

    scaleSize.setIcon(new javax.swing.ImageIcon(getClass().getResource("/scale.png"))); // NOI18N
    scaleSize.setToolTipText("Scale Image");
    scaleSize.setFocusable(false);
    scaleSize.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    scaleSize.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    scaleSize.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        scaleSizeActionPerformed(evt);
      }
    });
    toolbar1.add(scaleSize);

    jLabel4.setText(":");
    toolbar1.add(jLabel4);

    fillMode.setIcon(new javax.swing.ImageIcon(getClass().getResource("/fillmode.png"))); // NOI18N
    fillMode.setToolTipText("Fill Mode");
    fillMode.setFocusable(false);
    fillMode.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    fillMode.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    toolbar1.add(fillMode);

    fillAlpha.setIcon(new javax.swing.ImageIcon(getClass().getResource("/fillAlpha.png"))); // NOI18N
    fillAlpha.setToolTipText("Fill setting Transparent Level (Alpha)");
    fillAlpha.setFocusable(false);
    fillAlpha.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    fillAlpha.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    fillAlpha.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        fillAlphaActionPerformed(evt);
      }
    });
    toolbar1.add(fillAlpha);

    fillEdge.setIcon(new javax.swing.ImageIcon(getClass().getResource("/fillEdge.png"))); // NOI18N
    fillEdge.setToolTipText("Fill edges only");
    fillEdge.setFocusable(false);
    fillEdge.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    fillEdge.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    toolbar1.add(fillEdge);

    round.setIcon(new javax.swing.ImageIcon(getClass().getResource("/round.png"))); // NOI18N
    round.setToolTipText("Rounded Box");
    round.setFocusable(false);
    round.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    round.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    round.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        roundActionPerformed(evt);
      }
    });
    toolbar1.add(round);

    selkeyclr.setIcon(new javax.swing.ImageIcon(getClass().getResource("/keyclr.png"))); // NOI18N
    selkeyclr.setToolTipText("Place selection box except for background color pixels.");
    selkeyclr.setFocusable(false);
    selkeyclr.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    selkeyclr.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    toolbar1.add(selkeyclr);

    selFillAlpha.setIcon(new javax.swing.ImageIcon(getClass().getResource("/selboxalpha.png"))); // NOI18N
    selFillAlpha.setToolTipText("Selection tool fills alpha");
    selFillAlpha.setFocusable(false);
    selFillAlpha.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    selFillAlpha.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    toolbar1.add(selFillAlpha);

    jLabel5.setText(":");
    toolbar1.add(jLabel5);

    selectFont.setIcon(new javax.swing.ImageIcon(getClass().getResource("/font.png"))); // NOI18N
    selectFont.setToolTipText("Select Font");
    selectFont.setFocusable(false);
    selectFont.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    selectFont.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    selectFont.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        selectFontActionPerformed(evt);
      }
    });
    toolbar1.add(selectFont);

    changeSize.setIcon(new javax.swing.ImageIcon(getClass().getResource("/size.png"))); // NOI18N
    changeSize.setToolTipText("Change Image Size");
    changeSize.setFocusable(false);
    changeSize.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    changeSize.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    changeSize.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        changeSizeActionPerformed(evt);
      }
    });
    toolbar1.add(changeSize);

    crop.setIcon(new javax.swing.ImageIcon(getClass().getResource("/selboxcrop.png"))); // NOI18N
    crop.setToolTipText("Crop Image");
    crop.setFocusable(false);
    crop.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    crop.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    crop.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        cropActionPerformed(evt);
      }
    });
    toolbar1.add(crop);

    backswap.setIcon(new javax.swing.ImageIcon(getClass().getResource("/backswap.png"))); // NOI18N
    backswap.setToolTipText("Alternate background checker pattern.");
    backswap.setFocusable(false);
    backswap.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    backswap.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    backswap.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        backswapActionPerformed(evt);
      }
    });
    toolbar1.add(backswap);

    toolbar2.setFloatable(false);
    toolbar2.setRollover(true);

    foreColor.setText("ForeColor");
    foreColor.setToolTipText("Fore Color");
    foreColor.setFocusable(false);
    foreColor.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    foreColor.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    foreColor.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        foreColorActionPerformed(evt);
      }
    });
    toolbar2.add(foreColor);

    swap.setIcon(new javax.swing.ImageIcon(getClass().getResource("/swap.png"))); // NOI18N
    swap.setToolTipText("Swap Colors");
    swap.setFocusable(false);
    swap.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    swap.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    swap.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        swapActionPerformed(evt);
      }
    });
    toolbar2.add(swap);

    backColor.setText("BackColor");
    backColor.setToolTipText("Back Color");
    backColor.setFocusable(false);
    backColor.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    backColor.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    backColor.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        backColorActionPerformed(evt);
      }
    });
    toolbar2.add(backColor);

    width.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "1px", "2px", "3px", "4px" }));
    width.setToolTipText("Line Width");
    width.setMaximumSize(new java.awt.Dimension(50, 28));
    toolbar2.add(width);

    paintMode.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Normal", "Transparent", "Gradient (cyclic)", "Gradient (acyclic)", "Gradient (radial - no cycle)", "Gradient (radial - reflect)", "Gradient (radial - repeat)", "Gaussian Blur", "Pixelate", "Chrome" }));
    paintMode.setToolTipText("Paint Mode");
    paintMode.setMaximumSize(new java.awt.Dimension(180, 28));
    paintMode.setMinimumSize(new java.awt.Dimension(1, 1));
    paintMode.setName(""); // NOI18N
    paintMode.setPreferredSize(new java.awt.Dimension(180, 20));
    paintMode.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        paintModeActionPerformed(evt);
      }
    });
    toolbar2.add(paintMode);

    colorLayer.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "ARGB", "A---", "-R--", "--G-", "---B" }));
    colorLayer.setToolTipText("Color Layer");
    colorLayer.setLightWeightPopupEnabled(false);
    colorLayer.setMaximumSize(new java.awt.Dimension(70, 28));
    colorLayer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        colorLayerActionPerformed(evt);
      }
    });
    toolbar2.add(colorLayer);

    layersButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/layers.png"))); // NOI18N
    layersButton.setToolTipText("Show Image Layers Window");
    layersButton.setFocusable(false);
    layersButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
    layersButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
    layersButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        layersButtonActionPerformed(evt);
      }
    });
    toolbar2.add(layersButton);

    toolbar3.setFloatable(false);
    toolbar3.setRollover(true);

    jLabel1.setText("Threshold:");
    jLabel1.setToolTipText("0=match exact : 100=match all");
    toolbar3.add(jLabel1);

    threshold.setText("0%");
    threshold.setToolTipText("0=match exact : 100=match all");
    threshold.setMaximumSize(new java.awt.Dimension(30, 14));
    threshold.setMinimumSize(new java.awt.Dimension(25, 14));
    threshold.setPreferredSize(new java.awt.Dimension(25, 14));
    toolbar3.add(threshold);

    thresholdSlider.setMaximum(255);
    thresholdSlider.setToolTipText("0=match exact : 100=match all");
    thresholdSlider.setValue(0);
    thresholdSlider.setEnabled(false);
    thresholdSlider.setMaximumSize(new java.awt.Dimension(120, 23));
    thresholdSlider.setMinimumSize(new java.awt.Dimension(100, 23));
    thresholdSlider.setPreferredSize(new java.awt.Dimension(100, 23));
    thresholdSlider.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(javax.swing.event.ChangeEvent evt) {
        thresholdSliderStateChanged(evt);
      }
    });
    toolbar3.add(thresholdSlider);

    jLabel2.setText("Transparent:");
    jLabel2.setToolTipText("0=opaque : 100=transparent");
    toolbar3.add(jLabel2);

    alpha.setText("0%");
    alpha.setToolTipText("0=transparent : 100=opaque");
    alpha.setMaximumSize(new java.awt.Dimension(30, 14));
    alpha.setMinimumSize(new java.awt.Dimension(25, 14));
    alpha.setPreferredSize(new java.awt.Dimension(25, 14));
    toolbar3.add(alpha);

    alphaSlider.setMaximum(255);
    alphaSlider.setToolTipText("0=transparent : 100=opaque");
    alphaSlider.setValue(0);
    alphaSlider.setEnabled(false);
    alphaSlider.setMaximumSize(new java.awt.Dimension(120, 23));
    alphaSlider.setMinimumSize(new java.awt.Dimension(100, 23));
    alphaSlider.setPreferredSize(new java.awt.Dimension(100, 23));
    alphaSlider.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(javax.swing.event.ChangeEvent evt) {
        alphaSliderStateChanged(evt);
      }
    });
    toolbar3.add(alphaSlider);

    jLabel6.setText("Zoom:");
    toolbar3.add(jLabel6);

    zoom.setMaximum(5);
    zoom.setPaintLabels(true);
    zoom.setValue(2);
    zoom.setMaximumSize(new java.awt.Dimension(120, 23));
    zoom.setMinimumSize(new java.awt.Dimension(100, 23));
    zoom.setPreferredSize(new java.awt.Dimension(100, 23));
    zoom.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(javax.swing.event.ChangeEvent evt) {
        zoomStateChanged(evt);
      }
    });
    toolbar3.add(zoom);

    zoomText.setText("100%");
    toolbar3.add(zoomText);

    tabs.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT);
    tabs.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(javax.swing.event.ChangeEvent evt) {
        tabsStateChanged(evt);
      }
    });

    status.setText("status");

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
    this.setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addComponent(toolbar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
      .addComponent(toolbar1, javax.swing.GroupLayout.DEFAULT_SIZE, 639, Short.MAX_VALUE)
      .addComponent(status)
      .addComponent(tabs)
      .addComponent(toolbar3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addComponent(toolbar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(toolbar2, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(toolbar3, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(tabs, javax.swing.GroupLayout.PREFERRED_SIZE, 423, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(status, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
    );
  }// </editor-fold>//GEN-END:initComponents

  private void tabsStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabsStateChanged
    if (curIdx != -1) {
      unselectTool(curIdx);
      updateStatus();
    }
    int idx = getidx();
    curIdx = idx;
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    int scale = (int)pc.scale;
    switch (scale) {
      case 25: zoom.setValue(0); break;
      case 50: zoom.setValue(1); break;
      case 100: zoom.setValue(2); break;
      case 200: zoom.setValue(3); break;
      case 400: zoom.setValue(4); break;
      case 800: zoom.setValue(5); break;
    }
    colorLayer.setSelectedIndex(pc.getColorLayer());
    if (layers != null) {
      layers.setup(pc);
    }
  }//GEN-LAST:event_tabsStateChanged

  private void selBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selBoxActionPerformed
    if (selectedTool == tools.selBox) return;
    unselectTool(getidx());
    selectTool(tools.selBox);
  }//GEN-LAST:event_selBoxActionPerformed

  private void fillActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fillActionPerformed
    if (selectedTool == tools.fill) return;
    unselectTool(getidx());
    selectTool(tools.fill);
  }//GEN-LAST:event_fillActionPerformed

  private void pickColorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pickColorActionPerformed
    if (selectedTool == tools.pickColor) return;
    unselectTool(getidx());
    selectTool(tools.pickColor);
  }//GEN-LAST:event_pickColorActionPerformed

  private void pencilActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pencilActionPerformed
    if (selectedTool == tools.pencil) return;
    unselectTool(getidx());
    selectTool(tools.pencil);
  }//GEN-LAST:event_pencilActionPerformed

  private void textActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_textActionPerformed
    if (selectedTool == tools.text) return;
    unselectTool(getidx());
    selectTool(tools.text);
  }//GEN-LAST:event_textActionPerformed

  private void curveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_curveActionPerformed
    if (selectedTool == tools.curve) return;
    unselectTool(getidx());
    selectTool(tools.curve);
  }//GEN-LAST:event_curveActionPerformed

  private void lineActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_lineActionPerformed
    if (selectedTool == tools.line) return;
    unselectTool(getidx());
    selectTool(tools.line);
  }//GEN-LAST:event_lineActionPerformed

  private void boxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_boxActionPerformed
    if (selectedTool == tools.box) return;
    unselectTool(getidx());
    selectTool(tools.box);
  }//GEN-LAST:event_boxActionPerformed

  private void circleActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_circleActionPerformed
    if (selectedTool == tools.circle) return;
    unselectTool(getidx());
    selectTool(tools.circle);
  }//GEN-LAST:event_circleActionPerformed

  private void foreColorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_foreColorActionPerformed
    foreClr = selectClr(foreClr, "Select foreground colour");
    updateClr(foreColor, foreClr);
  }//GEN-LAST:event_foreColorActionPerformed

  private void backColorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backColorActionPerformed
    backClr = selectClr(backClr, "Select background colour");
    updateClr(backColor, backClr);
  }//GEN-LAST:event_backColorActionPerformed

  private void subActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_subActionPerformed
    if (selectedTool == tools.sub) return;
    unselectTool(getidx());
    selectTool(tools.sub);
  }//GEN-LAST:event_subActionPerformed

  private void swapActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_swapActionPerformed
    swapColors();
  }//GEN-LAST:event_swapActionPerformed

  private void rotateCWActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateCWActionPerformed
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    pc.rotateCW();
    pc.resizeBorder();
    pc.parentPanel.revalidate();
    pc.repaint();
  }//GEN-LAST:event_rotateCWActionPerformed

  private void rotateCCWActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateCCWActionPerformed
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    pc.rotateCCW();
    pc.resizeBorder();
    pc.parentPanel.revalidate();
    pc.repaint();
  }//GEN-LAST:event_rotateCCWActionPerformed

  private void flipVertActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_flipVertActionPerformed
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    pc.flipVert();
    pc.repaint();
  }//GEN-LAST:event_flipVertActionPerformed

  private void flipHorzActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_flipHorzActionPerformed
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    pc.flipHorz();
    pc.repaint();
  }//GEN-LAST:event_flipHorzActionPerformed

  private void scaleSizeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleSizeActionPerformed
    GetXY dialog = new GetXY(frame, true, "Scale Image (percentage)", 100, 100);
    dialog.setVisible(true);
    if (dialog.w <= 0) return;
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    int orgLayer = pc.getColorLayer();
    if (orgLayer != 0) {
      pc.changeColorLayer(0);
    }
    pc.scaleImage(dialog.w, dialog.h);
    pc.resizeBorder();
    if (orgLayer != 0) {
      pc.changeColorLayer(orgLayer);
    }
    pc.parentPanel.revalidate();
    pc.repaint();
  }//GEN-LAST:event_scaleSizeActionPerformed

  private void selectFontActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectFontActionPerformed
    JFontChooser fc = new JFontChooser(null);
    fc.showDialog(textFont);
    Font newFont = fc.getFont();
    if (newFont == null) return;
    textFont = newFont;
  }//GEN-LAST:event_selectFontActionPerformed

  private void changeSizeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeSizeActionPerformed
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    int ox = pc.getUnscaledWidth();
    int oy = pc.getUnscaledHeight();
    GetXY dialog = new GetXY(frame, true, "Set Image Size (pixels)", ox, oy);
    dialog.setVisible(true);
    if ((dialog.w <= 0) || (dialog.h <= 0)) return;
    changeSize(pc, dialog.w - ox, dialog.h - oy, false);
  }//GEN-LAST:event_changeSizeActionPerformed

  private void roundActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_roundActionPerformed
    if (round.isSelected()) {
      GetXY getarcs = new GetXY(null, true, "Get Arc X/Y", arcX, arcY);
      getarcs.setVisible(true);
      if (getarcs.w == -1) {
        round.setSelected(false);
        return;
      }
      arcX = getarcs.w;
      arcY = getarcs.h;
    }
  }//GEN-LAST:event_roundActionPerformed

  private void colorLayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_colorLayerActionPerformed
    layerChanged();
  }//GEN-LAST:event_colorLayerActionPerformed

  private void paintModeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_paintModeActionPerformed
    paintModeChanged();
  }//GEN-LAST:event_paintModeActionPerformed

  private void backswapActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backswapActionPerformed
    int idx = getidx();
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (pc == null) return;
    pc.swap = !pc.swap;
    pc.backClear();
    pc.repaint();
  }//GEN-LAST:event_backswapActionPerformed

  private void layersButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_layersButtonActionPerformed
    if (layers != null) {
      layers.dispose();
    } else {
      int idx = getidx();
      if (idx == -1) return;
      PaintCanvas pc = imageTabs.get(idx).pc;
      if (pc == null) return;
      layers = new LayersWindow(this);
      layers.setup(pc);
      layers.setVisible(true);
      Point pt = layersButton.getLocationOnScreen();
      pt.y += layersButton.getHeight();
      layers.setLocation(pt);
    }
  }//GEN-LAST:event_layersButtonActionPerformed

  private void thresholdSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_thresholdSliderStateChanged
    threshold.setText("" + getThresholdPercent() + "%");
  }//GEN-LAST:event_thresholdSliderStateChanged

  private void alphaSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_alphaSliderStateChanged
    alpha.setText("" + getAlphaPercent() + "%");
  }//GEN-LAST:event_alphaSliderStateChanged

  private void zoomStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_zoomStateChanged
    changeScale();
  }//GEN-LAST:event_zoomStateChanged

  private void fillAlphaActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fillAlphaActionPerformed
    if (selectedTool == tools.fill) {
      alphaSlider.setEnabled(fillAlpha.isSelected());
    }
  }//GEN-LAST:event_fillAlphaActionPerformed

  private void cropActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cropActionPerformed
    crop();
  }//GEN-LAST:event_cropActionPerformed

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JLabel alpha;
  private javax.swing.JSlider alphaSlider;
  private javax.swing.JButton backColor;
  private javax.swing.JButton backswap;
  private javax.swing.JToggleButton box;
  private javax.swing.JButton changeSize;
  private javax.swing.JToggleButton circle;
  private javax.swing.JComboBox colorLayer;
  private javax.swing.JButton crop;
  private javax.swing.JToggleButton curve;
  private javax.swing.JToggleButton fill;
  private javax.swing.JToggleButton fillAlpha;
  private javax.swing.JToggleButton fillEdge;
  private javax.swing.JToggleButton fillMode;
  private javax.swing.JButton flipHorz;
  private javax.swing.JButton flipVert;
  private javax.swing.JButton foreColor;
  private javax.swing.ButtonGroup group;
  private javax.swing.JLabel jLabel1;
  private javax.swing.JLabel jLabel2;
  private javax.swing.JLabel jLabel3;
  private javax.swing.JLabel jLabel4;
  private javax.swing.JLabel jLabel5;
  private javax.swing.JLabel jLabel6;
  private javax.swing.JButton layersButton;
  private javax.swing.JToggleButton line;
  private javax.swing.JComboBox paintMode;
  private javax.swing.JToggleButton pencil;
  private javax.swing.JToggleButton pickColor;
  private javax.swing.JButton rotateCCW;
  private javax.swing.JButton rotateCW;
  private javax.swing.JToggleButton round;
  private javax.swing.JButton scaleSize;
  private javax.swing.JToggleButton selBox;
  private javax.swing.JToggleButton selFillAlpha;
  private javax.swing.JButton selectFont;
  private javax.swing.JToggleButton selkeyclr;
  private javax.swing.JTextField status;
  private javax.swing.JToggleButton sub;
  private javax.swing.JButton swap;
  private javax.swing.JTabbedPane tabs;
  private javax.swing.JToggleButton text;
  private javax.swing.JLabel threshold;
  private javax.swing.JSlider thresholdSlider;
  private javax.swing.JToolBar toolbar1;
  private javax.swing.JToolBar toolbar2;
  private javax.swing.JToolBar toolbar3;
  private javax.swing.JComboBox width;
  private javax.swing.JSlider zoom;
  private javax.swing.JLabel zoomText;
  // End of variables declaration//GEN-END:variables

  //global data
  private JFrame frame;
  public boolean active = true;
  public enum tools { selBox, fill, pickColor, pencil, text, curve, line, box, circle, sub };
/*  public enum modes {
    Normal, Transparent, Gradient_cyclic, Gradient_acyclic, Gradient_radial_no_cycle
    ,Gradient_radial_reflect, Gradient_radial_repeat
  };*/
  public tools selectedTool = tools.selBox;
  public int foreClr = 0x000000;
  public int backClr = 0xffffff;
  public int selClr = 0x000000;
  public int init_x = 256, init_y = 256;
  public boolean haveSel;
  public int selX1, selY1, selX2, selY2;
  public int clipBoard[], cbX, cbY;
  public int cx[] = new int[4], cy[] = new int[4];  //curve points
  public int cpt = -1;  //current curve point (0-3)
  public int gx[] = new int[2], gy[] = new int[2];  //grad points
  public int gfx, gfy;  //grad focus point (radial)
  public boolean getGradPoints = false;
  public boolean getGradFocus = false;
  public String textText = "";
  public Font textFont = new Font("Default", Font.PLAIN, 12);
  public int curIdx = -1;
  public int arcX = 25, arcY = 25;
  public Config config;
  public LayersWindow layers;
  public JFImage rotateImg;
  public JFImage pixel;

  private String configFolder = JF.getUserPath();
  private String configFile = "/.jfpaint.xml";
  private String currentPath;
  private int filter_radius;
  private int filter_pixelSize;  //pixelation
  private float filter_amount, filter_exposure;
  private float rotate;
  private int scretchDir;

  public static class Config {
    public String code;
  }

  private void loadConfig() {
    defaultConfig();
    try {
      XML xml = new XML();
      FileInputStream fis = new FileInputStream(configFolder + configFile);
      xml.read(fis);
      xml.writeClass(config);
    } catch (FileNotFoundException e1) {
      defaultConfig();
    } catch (Exception e2) {
      JFLog.log(e2);
      defaultConfig();
    }
  }

  private void defaultConfig() {
    config = new Config();
  }

  private void saveConfig() {
    try {
      XML xml = new XML();
      FileOutputStream fos = new FileOutputStream(configFolder + configFile);
      xml.readClass("jfpaint", config);
      xml.write(fos);
      fos.close();
    } catch (Exception e) {
      JFLog.log(e);
    }
  }

  private class PanelLayout implements LayoutManager {
//    private Vector<Component> list = new Vector<Component>();
    public void addLayoutComponent(String string, Component cmp) {
//      list.add(cmp);
    }

    public void removeLayoutComponent(Component cmp) {
//      list.remove(cmp);
    }

    public Dimension preferredLayoutSize(Container c) {
      return new Dimension(1, 1);
    }

    public Dimension minimumLayoutSize(Container c) {
      return new Dimension(1, 1);
    }

    public void layoutContainer(Container c) {
      //assumes images are added Center,East,South
      try {
        Dimension d1, d2, d3, ds;
        int cnt = c.getComponentCount();
        int x = c.getWidth();
        int y = c.getHeight();
        d1 = toolbar1.getPreferredSize();
        toolbar1.setBounds(0, 0, x, d1.height);
        d2 = toolbar2.getPreferredSize();
        toolbar2.setBounds(0, d1.height, x, d2.height);
        d3 = toolbar3.getPreferredSize();
        toolbar3.setBounds(0, d1.height + d2.height, x, d3.height);
        ds = status.getPreferredSize();
        tabs.setBounds(0, d1.height + d2.height + d3.height, x, y - (d1.height + d2.height + d3.height + ds.height));
        status.setBounds(0, y - ds.height, x, ds.height);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  private class ImageLayout implements LayoutManager {
//    private Vector<Component> list = new Vector<Component>();
    public void addLayoutComponent(String string, Component cmp) {
//      list.add(cmp);
    }

    public void removeLayoutComponent(Component cmp) {
//      list.remove(cmp);
    }

    public Dimension preferredLayoutSize(Container c) {
      int cnt = c.getComponentCount();
      if (cnt != 4) return new Dimension(1, 1);
      PaintCanvas pc = (PaintCanvas)c.getComponent(0);
      return new Dimension(pc.getScaledWidth() + 10, pc.getScaledHeight() + 10);
    }

    public Dimension minimumLayoutSize(Container c) {
      return preferredLayoutSize(c);
    }

    public void layoutContainer(Container c) {
      //assumes images are added Center,East,South,Corner
      int cnt = c.getComponentCount();
      if (cnt != 4) return;
      PaintCanvas pc = (PaintCanvas)c.getComponent(0);
      int x = pc.getScaledWidth();
      int y = pc.getScaledHeight();
//System.out.println("layout:" + x + "," + y);
      pc.setBounds(0, 0, x, y);
      Component img1 = c.getComponent(1);
      img1.setBounds(x, 0, 10, y);
      Component img2 = c.getComponent(2);
      img2.setBounds(0, y, x, 10);
      Component img3 = c.getComponent(3);
      img3.setBounds(x, y, 10, 10);
    }
  }

  private class ImageTab {
    PaintCanvas pc;
    JPanel panel;
    JScrollPane scroll;
    File filename;
  };
  private Vector<ImageTab> imageTabs = new Vector<ImageTab>();

  public void openTab() {
    JFileChooser chooser = new JFileChooser();
    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("JFPAINT", "jfpaint"));
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("JPEG", "jpg", "jpeg"));
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("PNG", "png"));
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("BMP", "bmp"));
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("XPM", "xpm"));
    chooser.setMultiSelectionEnabled(false);
    chooser.setCurrentDirectory(new File(currentPath));
    if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) return;
    loadTab(chooser.getSelectedFile().toString());
  }

  private void loadTab(String filename) {
    if (filename.length() == 0) return;
    int idx = getidx();
    ImageTab tab = imageTabs.get(idx);
    boolean emptyFile;
    //check if current page is "untitled" and !dirty
    if (tab.filename.toString().equals("untitled") && imageTabs.get(idx).pc.dirty == false) {
      //load on current page
      tab.filename = new File(filename);
      emptyFile = tab.filename.length() == 0;
    } else {
      addTab("newfile");
      idx = tabs.getTabCount() - 1;
      tab = imageTabs.get(idx);
      tab.filename = new File(filename);
      emptyFile = tab.filename.length() == 0;
    }
    currentPath = tab.filename.getAbsoluteFile().getParent();
    if (currentPath == null) currentPath = JF.getUserPath() + "/Pictures";
    String name = tab.filename.toString();
    int fidx = name.lastIndexOf("/");
    if (fidx != -1) name = name.substring(fidx+1);
    tabs.setTitleAt(idx, name);
    PaintCanvas pc = tab.pc;
    if (!emptyFile && !loadImage(pc, filename)) {
      closeTab(false);
      if (tabs.getTabCount() == 0) addTab("untitled");
      JFAWT.showError("Error", "Failed to load file");
      return;
    }
    pc.grabFocus();
    pc.resizeBorder();
    pc.parentPanel.revalidate();
    updateStatus();
  }

  public void loadFiles(String files[]) {
    if (files == null) return;
    for(int a=0;a<files.length;a++) {
      loadTab(files[a]);
    }
  }

  private ImageTab addTab(String title) {
    ImageTab tab = new ImageTab();
    tab.panel = new JPanel(new ImageLayout());
    tab.scroll = new JScrollPane(tab.panel);
    tab.pc = new PaintCanvas(tab.panel, tab.scroll);
    tab.pc.setImageSize(init_x, init_y);
    tab.pc.img[0].fill(0,0,init_x,init_y,backClr);
    tab.pc.createBorders();
    tab.panel.add(tab.pc, "CENTER");
    tab.panel.add(tab.pc.border_east, "EAST");
    tab.panel.add(tab.pc.border_south, "SOUTH");
    tab.panel.add(tab.pc.border_corner, "CORNER");
    tab.pc.resizeBorder();
    tab.filename = new File(title);
    tab.pc.dirty = false;
    imageTabs.add(tab);
    tabs.addTab(title, tab.scroll);
    tabs.setSelectedComponent(tab.scroll);
    tab.pc.requestFocus();
    if (layers != null) {
      layers.setup(tab.pc);
    }
    return tab;
  }

  private int getidx() { return tabs.getSelectedIndex(); }

  private boolean loadImage(PaintCanvas pc, String filename) {
    pc.disableScale = true;
    JFImage img = new JFImage();
    String format = getFormat(filename);
    if (format == null) return false;
    boolean result, multi = false;
    if (format.equals("jfpaint")) {
      multi = true;
      try {
        JFPaint imgs;
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        imgs = (JFPaint)ois.readObject();
        ois.close();
        fis.close();
        int w = 0,h = 0;
        for(int a=0;a<imgs.images.length;a++) {
          img = new JFImage();
          ByteArrayInputStream bais = new ByteArrayInputStream(imgs.images[a].png);
          if (!img.loadPNG(bais)) throw new Exception("jfpaint sub-png load failed");
          if (a == 0) {
            w = img.getWidth();
            h = img.getHeight();
            pc.setImageSize(w, h);
          } else {
            pc.addImageLayer();
          }
          pc.setImageLayer(a);
          int px[] = img.getPixels();
          pc.img[a].putPixels(px, 0, 0, w, h, 0);
          pc.name[a] = imgs.images[a].name;
        }
        pc.setImageLayer(0);
        result = true;
      } catch (Exception e) {
        JFAWT.showError("Error", e.toString());
        result = false;
      }
    }
    else if (format.equals("bmp"))
      result = img.loadBMP(filename, 0);
    else if (format.equals("svg"))
      result = img.loadSVG(filename);
    else if (format.equals("jpg"))
      result = img.loadJPG(filename);
    else if (format.equals("xpm"))
      result = img.loadXPM(filename);
    else
      result = img.load(filename);
    if (result && !multi) {
      int w = img.getWidth();
      int h = img.getHeight();
      pc.setImageSize(w, h);
      int px[] = img.getPixels();
      pc.img[pc.getImageLayer()].putPixels(px, 0, 0, w, h, 0);
    }
    pc.disableScale = false;
    return result;
  }

  private void updateStatus() {
    int idx = getidx();
    if (idx == -1) {status.setText("?"); return;}
    if (getGradPoints) {
      status.setText("Draw a line to define Gradient start and end points.");
      return;
    }
    if (getGradFocus) {
      status.setText("Click a point to define Gradient focal point.");
      return;
    }
    ImageTab tab = imageTabs.get(idx);
    String str = "size:" + tab.pc.getUnscaledWidth() + "x" + tab.pc.getUnscaledHeight();
    str += " mouse: " + tab.pc.mx + "," + tab.pc.my;
    if (tab.pc.button == MouseEvent.BUTTON1) str += " box: " + Math.abs(tab.pc.mx - tab.pc.sx + 1) + "x" + Math.abs(tab.pc.my - tab.pc.sy + 1);
    status.setText(str);
  }

  private int selectClr(int oldClr, String name) {
    Color newClr = JColorChooser.showDialog(this, name, new Color(oldClr));
    if (newClr == null) return oldClr;
    return newClr.getRGB() & JFImage.RGB_MASK;
  }

  private void updateClr(JButton button, int clr) {
    JFImage blk = new JFImage(16,16);
    blk.fill(0,0,16,16,clr);
    button.setIcon(blk);
    button.setText("");
  }

  public void newTab() {
    GetXY dialog = new GetXY(frame, true, "New Image (pixels)", init_x, init_y);
    dialog.setVisible(true);
    if (dialog.w == -1) return;
    int idx = getidx();
    ImageTab tab = imageTabs.get(idx);
    if (!(tab.filename.toString().equals("untitled") && imageTabs.get(idx).pc.dirty == false)) {
      addTab("untitled");
      idx = tabs.getTabCount() - 1;
      tab = imageTabs.get(idx);
    }
    tab.pc.setImageSize(dialog.w, dialog.h);
    tab.pc.img[tab.pc.getImageLayer()].fill(0,0,dialog.w,dialog.h,backClr);
    repaint();
  }

  public boolean closeTab(boolean exiting) {
    int idx = getidx();
    if (tabs.getTabCount() == 0) return true;
    if (imageTabs.get(idx).pc.dirty) {
      switch (JFAWT.showConfirm3("Save?", "Save first?")) {
        case JFAWT.YES:
          if (!saveTab()) return false;
        case JFAWT.CANCEL:
          return false;
        case JFAWT.NO:
          break;
      }
    }
    curIdx = -1;
    imageTabs.remove(idx);
    tabs.remove(idx);
    if (exiting) return true;
    if (tabs.getTabCount() == 0) addTab("untitled");
    return true;
  }

  public boolean saveTab() {
    int idx = getidx();
    if (imageTabs.get(idx).filename.toString().equals("untitled")) {
      return saveAs();
    }
    PaintCanvas pc = imageTabs.get(idx).pc;
    String filename = imageTabs.get(idx).filename.toString();
    String format = getFormat(filename);
    if (format == null) return false;
    boolean saved = false;
    pc.disableScale = true;
    pc.clearUndo();
    pc.applyColorLayer();
    if (format.equals("jfpaint")) {
      int cnt = pc.getImageLayers();
      JFPaint imgs = new JFPaint();
      imgs.images = new JFPaintImage[cnt];
      try {
        for(int a=0;a<cnt;a++) {
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          if (!pc.img[a].savePNG(baos)) throw new Exception("jfpaint sub-png save failed");
          imgs.images[a] = new JFPaintImage();
          imgs.images[a].png = baos.toByteArray();
          imgs.images[a].name = pc.name[a];
        }
        FileOutputStream fos = new FileOutputStream(filename);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(imgs);
        oos.close();
        fos.close();
        return true;
      } catch (Exception e) {
        JFAWT.showError("Error", e.toString());
        return false;
      }
    } else {
      if (pc.getImageLayers() > 1) {
        if (!JFAWT.showConfirm("Combine Layers?", "Saving in this format will combine all layers, are you sure?")) return false;
      }
      JFImage img = pc.combineImageLayers();
      if (format.equals("bmp"))
        saved = img.saveBMP(filename);
      else if (format.equals("svg"))
        saved = img.saveSVG(filename);
      else if (format.equals("jpg"))
        saved = img.saveJPG(filename);
      else
        saved = img.save(filename, format);
    }
    pc.disableScale = false;
    if (saved) pc.dirty = false;
    return saved;
  }

  public boolean saveAs() {
    int idx = getidx();
    JFileChooser chooser = new JFileChooser();
    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("JFPAINT", "jfpaint"));
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("JPEG", "jpg", "jpeg"));
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("PNG", "png"));
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("BMP", "bmp"));
    chooser.addChoosableFileFilter(new FileNameExtensionFilter("SVG", "svg"));
    chooser.setMultiSelectionEnabled(false);
    chooser.setCurrentDirectory(new File(currentPath));
    if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
      ImageTab tab = imageTabs.get(idx);
      tab.pc.setDirty();
      tab.filename = chooser.getSelectedFile();
      String format = getFormat(tab.filename.toString());
      if (format == null) {
        String ext = chooser.getFileFilter().getDescription().toLowerCase();
        if (ext.equals("all files")) {
          if (tab.pc.getImageLayers() == 1)
            ext = "png"; //default if one image layer
          else
            ext = "jfpaint";  //default if > 1 image layer
        }
        if (ext.equals("jpeg")) ext = "jpg";
        tab.filename = new File(tab.filename.toString() + "." + ext);
      }
      currentPath = tab.filename.getAbsoluteFile().getParent();
      if (currentPath == null) currentPath = JF.getUserPath() + "/Pictures";
      String name = tab.filename.toString();
      int fidx = name.lastIndexOf("/");
      if (fidx != -1) name = name.substring(fidx+1);
      tabs.setTitleAt(idx, name);
      return saveTab();
    }
    return false;
  }

  private void selectAll() {
    int idx = getidx();
    unselectTool(idx);
    selBox.setSelected(true);
    selectTool(tools.selBox);
    PaintCanvas pc = imageTabs.get(idx).pc;
    selX1 = selY1 = 0;
    selX2 = pc.img[pc.getImageLayer()].getWidth()-1;
    selY2 = pc.img[pc.getImageLayer()].getHeight()-1;
    haveSel = true;
    cutSel();
    pasteSel(selX1, selY1, false);
    pc.drag = true;
  }

  private String getFormat(String filename) {
    int idx = filename.lastIndexOf(".");
    if (idx == -1) return null;
    String format = filename.substring(idx+1).toLowerCase();
    if (format.equals("jfpaint")) return "jfpaint";
    if (format.equals("png")) return "png";
    if (format.equals("bmp")) return "bmp";
    if (format.equals("jpg")) return "jpg";
    if (format.equals("jpeg")) return "jpg";
    if (format.equals("svg")) return "svg";
    if (format.equals("xpm")) return "xpm";
    System.out.println("Unsupported format:" + format);
    return null;
  }

  private void selectTool(tools tool) {
    selectedTool = tool;
    switch (tool) {
      case fill:
        thresholdSlider.setEnabled(true);
        alphaSlider.setEnabled(fillAlpha.isSelected() || paintMode.getSelectedIndex() == 1);
        break;
      case sub:
        thresholdSlider.setEnabled(true);
        alphaSlider.setEnabled(paintMode.getSelectedIndex() == 1);
        break;
      default:
        thresholdSlider.setEnabled(false);
        alphaSlider.setEnabled(paintMode.getSelectedIndex() == 1);
        break;
    }
  }

  private void unselectTool(int idx) {
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    pc.disableScale = true;
    switch (selectedTool) {
      case selBox:
        if (pc.drag) { drawSel(pc); clearSel(pc); pc.drag = false; }
        pc.foreClear();
        break;
      case text:
        if (pc.drag) { drawText(pc); clearSel(pc); pc.drag = false; }
        pc.foreClear();
        break;
      case curve:
        cpt = -1;
        break;
    }
    pc.disableScale = false;
  }

  private void print() {
    //TODO
  }

  public void delSel() {
    if (selectedTool != tools.selBox) return;
    if (!haveSel) return;
    int tmp;
    if (selX1 > selX2) {tmp=selX1; selX1=selX2; selX2=tmp;}
    if (selY1 > selY2) {tmp=selY1; selY1=selY2; selY2=tmp;}
    int idx = getidx();
    int w = selX2-selX1+1;
    int h = selY2-selY1+1;
    PaintCanvas pc = imageTabs.get(idx).pc;
    pc.img[pc.getImageLayer()].fill(selX1,selY1,w,h,backClr);
    clearSel(pc);
    pc.drag = false;
  }

  public void cutSel() {
    if (selectedTool != tools.selBox) return;
    if (!haveSel) return;
    int tmp;
    if (selX1 > selX2) {tmp=selX1; selX1=selX2; selX2=tmp;}
    if (selY1 > selY2) {tmp=selY1; selY1=selY2; selY2=tmp;}
    int idx = getidx();
    cbX = selX2-selX1+1;
    cbY = selY2-selY1+1;
    PaintCanvas pc = imageTabs.get(idx).pc;
    pc.disableScale = true;
    JFImage clip = new JFImage(cbX,cbY);
    clipBoard = pc.img[pc.getImageLayer()].getPixels(selX1,selY1,cbX,cbY);
    clip.putPixels(clipBoard,0,0,cbX,cbY,0);
    try {JFClipboard.writeImage(clip.getImage());} catch (Exception e) {e.printStackTrace();}
    int layer = pc.getImageLayer();
    if (layer == 0) {
      pc.img[layer].fill(selX1,selY1,cbX,cbY,backClr,!selFillAlpha.isSelected());
    } else {
      pc.img[layer].fill(selX1,selY1,cbX,cbY,backClr,true);  //alpha = transparent
    }
    pc.disableScale = false;
  }

  public void copySel() {
    if (selectedTool != tools.selBox) return;
    if (!haveSel) return;
    int tmp;
    if (selX1 > selX2) {tmp=selX1; selX1=selX2; selX2=tmp;}
    if (selY1 > selY2) {tmp=selY1; selY1=selY2; selY2=tmp;}
    int idx = getidx();
    cbX = selX2-selX1+1;
    cbY = selY2-selY1+1;
    PaintCanvas pc = imageTabs.get(idx).pc;
    JFImage clip = new JFImage(cbX,cbY);
    clipBoard = pc.img[pc.getImageLayer()].getPixels(selX1,selY1,cbX,cbY);
    clip.putPixels(clipBoard,0,0,cbX,cbY,0);
    try {JFClipboard.writeImage(clip.getImage());} catch (Exception e) {e.printStackTrace();}
  }

  public void pasteSel(int x, int y, boolean sysClipBoard) {
    if (colorLayer.getSelectedIndex() != 0) return;
    rotate = 0f;
    if (clipBoard == null || sysClipBoard) {
      try {
        java.awt.Image img = JFClipboard.readImage();
        if (img == null) return;
        JFImage image = JFClipboard.convertImage(img);
        cbX = image.getWidth();
        cbY = image.getHeight();
        clipBoard = image.getPixels();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    int idx = getidx();
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (selectedTool != tools.selBox) {
      unselectTool(idx);
      selBox.setSelected(true);
      selectTool(tools.selBox);
    }
    pc.disableScale = true;
    minSize(pc, x + cbX, y + cbY);
    selX1 = x;
    selY1 = y;
    selX2 = x+cbX;
    selY2 = y+cbY;
    haveSel = true;
    foreDrawSel(pc);
    pc.drag = true;
    pc.disableScale = false;
  }

  private void clearSel(PaintCanvas pc) {
    pc.foreClear();
    haveSel = false;
  }

  private void drawSel(PaintCanvas pc) {
    if (cbX == 0 || cbY == 0) return;  //shouldn't happen ???
    int px[];
    if (selkeyclr.isSelected()) {
      int cnt = cbX * cbY;
      px = new int[cnt];
      System.arraycopy(clipBoard, 0, px, 0, cnt);
      for(int a=0;a<cnt;a++) {
        if ((px[a] & JFImage.RGB_MASK) == backClr) {
          px[a] = 0;
        }
      }
    } else {
      px = clipBoard;
    }
    pc.putPixels(px, selX1, selY1, selX2 - selX1, selY2 - selY1, cbX, cbY, rotate);
    pc.img[pc.getImageLayer()].repaint();
  }

  private void foreDrawSel(PaintCanvas pc) {
    int px[];
    if (selkeyclr.isSelected()) {
      int cnt = cbX * cbY;
      px = new int[cnt];
      System.arraycopy(clipBoard, 0, px, 0, cnt);
      for(int a=0;a<cnt;a++) {
        if ((px[a] & JFImage.RGB_MASK) == backClr) {
          px[a] = 0;
        }
      }
    } else {
      px = clipBoard;
    }
    pc.forePutPixels(px, selX1, selY1, selX2 - selX1, selY2 - selY1, cbX, cbY, rotate);
    pc.foreDrawSelBox(selX1,selY1,selX2,selY2,rotate);
  }

  private void drawText(PaintCanvas pc) {
    assignPaint(pc.cimg, true);
    pc.setFont(textFont);
    int x=selX1;
    int y=selY1;
    Rectangle2D rect = textFont.getMaxCharBounds(pc.img[pc.getImageLayer()].getGraphics2D().getFontRenderContext());
    int fy = (int)rect.getHeight();
    pc.drawText(textText.split("\n"), x, y, fy, 1, 1, rotate);
    textText = "";
  }

  private void foreDrawText(PaintCanvas pc) {
    FontRenderContext frc = pc.img[pc.getImageLayer()].getGraphics2D().getFontRenderContext();
    Rectangle2D rect = textFont.getMaxCharBounds(pc.img[pc.getImageLayer()].getGraphics2D().getFontRenderContext());
    int fx = (int)rect.getWidth();
    int fy = (int)rect.getHeight();
    int mx = 1;
    int my;
    int lx = 0;
    assignPaint(pc.fimg, true);
    pc.foreClear();
    pc.foreDrawSelBox(selX1, selY1, selX2, selY2, rotate);
    pc.foreSetFont(textFont);
    String text;
    if (pc.textCursor) {
      pc.textCursor = false;
      text = textText + "\u2588";
    } else {
      pc.textCursor = true;
      text = textText;
    }
    String lns[] = text.split("\n", -1);
    my = lns.length * fy;
    int x=selX1;
    int y=selY1;
    for(int a=0;a<lns.length;a++) {
      lx = (int)textFont.getStringBounds(lns[a], frc).getWidth() + 6;
      if (lx > mx) mx = lx;
    }
    pc.foreDrawText(lns, x, y, fy, 1, 1, rotate);
    if ((selX2 - selX1) < mx) selX2 = selX1 + mx;
    if ((selY2 - selY1) < my) selY2 = selY1 + my;
  }

  private void repaintTool(PaintCanvas pc) {
    if (!pc.drag) return;
    assignPaint(pc.fimg, pc.button == MouseEvent.BUTTON1);
    pc.disableScale = true;
    pc.foreClear();
    switch (selectedTool) {
      case selBox:
        foreDrawSel(pc);
        break;
      case text:
        foreDrawText(pc);
        break;
    }
    pc.repaint();
    pc.disableScale = false;
  }

  private void undo() {
    unselectTool(getidx());
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    pc.disableScale = true;
    pc.undo();
    pc.disableScale = false;
  }

  private void redo() {
    unselectTool(getidx());
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    pc.disableScale = true;
    pc.redo();
    pc.disableScale = false;
  }

  private void repaintImage() {
    int idx = getidx();
    imageTabs.get(idx).pc.repaint();
  }

  private void minSize(PaintCanvas pc, int w, int h) {
    //scaling on pc is already disabled
    int pw = pc.getUnscaledWidth();
    int ph = pc.getUnscaledHeight();
    int dx = 0;
    int dy = 0;
    if (w > pw) dx = w - pw;
    if (h > ph) dy = h - ph;
    if (dx == 0 && dy == 0) return;
    changeSize(pc, dx, dy, false);
  }

  private void changeSize(PaintCanvas pc, int dx, int dy, boolean scaled) {
    float orgScale = pc.scale;
    int orgLayer = pc.getColorLayer();
    int x = pc.getUnscaledWidth();
    int y = pc.getUnscaledHeight();
    if (x + dx < 1) {
      dx = -x + 1;
    }
    if (y + dy < 1) {
      dy = -y + 1;
    }
    if (scaled) {
      dx /= (pc.scale / 100f);
      dy /= (pc.scale / 100f);
    }
    if (orgLayer != 0) {
      pc.changeColorLayer(0);
    }
    if (orgScale != 100) pc.setScale(100);
    int cnt = pc.getImageLayers();
    int px[][] = new int[cnt][];
    for (int a=0;a<cnt;a++) {
      px[a] = pc.img[a].getPixels();
    }
    pc.setImageSize(x + dx,y + dy);
    for(int a=0;a<cnt;a++) {
      pc.img[a].putPixels(px[a], 0,0, x,y, 0);
      if (dx > 0) {
        if (a == 0)
          pc.img[a].fill(x,0,dx,y + dy,backClr);
        else
          pc.img[a].fill(x,0,dx,y + dy,backClr, true);
      }
      if (dy > 0) {
        if (a == 0)
          pc.img[a].fill(0,y,x + dx,dy,backClr);
        else
          pc.img[a].fill(0,y,x + dx,dy,backClr, true);
      }
      if ((dx > 0) && (dy > 0)) {
        if (a == 0)
          pc.img[a].fill(x,y,dx,dy,backClr);
        else
          pc.img[a].fill(x,y,dx,dy,backClr, true);
      }
    }
    if (orgScale != 100) pc.setScale(orgScale);
    if (orgLayer != 0) {
      pc.changeColorLayer(orgLayer);
    }
    pc.resizeBorder();
    repaintTool(pc);
    updateStatus();
  }

  private void paintModeChanged() {
    getGradPoints = false;
    getGradFocus = false;
    updateStatus();
    int mode = paintMode.getSelectedIndex();
    if (mode == 0) {
      fillAlpha.setEnabled(true);
      fillEdge.setEnabled(true);
    } else {
      fillAlpha.setEnabled(false);
      fillAlpha.setSelected(false);
      fillEdge.setEnabled(false);
      fillEdge.setSelected(false);
    }
    alphaSlider.setEnabled(false);
    GetValue dialog;
    GetValue2 dialog2;
    switch (mode) {
      case 0:  //normal
        break;
      case 1:  //transparent
        alphaSlider.setEnabled(true);
        break;
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
        getGradPoints = true;
        updateStatus();
        break;
      case 7:
        dialog = new GetValue(null, true, "Enter Gaussian Blur parameters", "radius", 2, 64, 5);
        dialog.setVisible(true);
        filter_radius = dialog.value;
        if (filter_radius == -1) filter_radius = 2;
        break;
      case 8:
        dialog = new GetValue(null, true, "Enter Pixelate parameters", "pixel size", 2, 64, 5);
        dialog.setVisible(true);
        filter_pixelSize = dialog.value;
        if (filter_pixelSize == -1) filter_pixelSize = 2;
        break;
      case 9:
        dialog2 = new GetValue2(null, true, "Enter Chrome parameters"
          , "amount", 0, 100, 50
          , "exposure", 0, 100, 100
        );
        dialog2.setVisible(true);
        filter_amount = dialog2.value1;
        if (filter_amount == -1) filter_pixelSize = 50;
        filter_amount /= 100f;
        filter_exposure = dialog2.value2;
        if (filter_exposure == -1) filter_exposure = 100;
        filter_exposure /= 100f;
        break;
    }
    if (mode >= 7 ) {
      switch (selectedTool) {
        case box:
          break;
        default:
          unselectTool(getidx());
          box.doClick();
          break;
      }
      pencil.setEnabled(false);
      fill.setEnabled(false);
      fillMode.setEnabled(false);
      text.setEnabled(false);
      curve.setEnabled(false);
      line.setEnabled(false);
      circle.setEnabled(false);
      round.setEnabled(false);
      selectFont.setEnabled(false);
      sub.setEnabled(false);
      thresholdSlider.setEnabled(false);
      rotateCW.setEnabled(false);
      rotateCCW.setEnabled(false);
      flipVert.setEnabled(false);
      flipHorz.setEnabled(false);
      selkeyclr.setEnabled(false);
      fillMode.setSelected(false);
    } else {
      pencil.setEnabled(true);
      fill.setEnabled(true);
      fillMode.setEnabled(true);
      text.setEnabled(true);
      curve.setEnabled(true);
      line.setEnabled(true);
      circle.setEnabled(true);
      round.setEnabled(true);
      selectFont.setEnabled(true);
      sub.setEnabled(true);
      thresholdSlider.setEnabled(true);
      rotateCW.setEnabled(true);
      rotateCCW.setEnabled(true);
      flipVert.setEnabled(true);
      flipHorz.setEnabled(true);
      selkeyclr.setEnabled(true);
    }
  }

  private int getAlphaLevel() {
    int al = alphaSlider.getValue();
    return 255 - al;
  }

  private int getAlphaPercent() {
    int al = alphaSlider.getValue();
    return al * 100 / 255;
  }

  private int getThresholdLevel() {
    int al = thresholdSlider.getValue();
    if (al < 0) al = 0;
    if (al > 255) al = 255;
    return al;
  }

  private int getThresholdPercent() {
    int al = thresholdSlider.getValue();
    if (al < 0) al = 0;
    if (al > 255) al = 255;
    return al * 100 / 255;
  }

  private float gradRadius() {
    float rise = Math.abs(gy[0] - gy[1]);
    float run = Math.abs(gx[0] - gx[1]);
    return (float)Math.sqrt(rise*rise + run*run);
  }

  private void assignPaint(JFImage img, boolean button1) {
    Paint paint = null;
    int clr;
    switch (paintMode.getSelectedIndex()) {
      case 0:  //normal
        if (button1) clr = foreClr; else clr = backClr;
        switch (colorLayer.getSelectedIndex()) {
          case 0:  //ARGB
            paint = new Color(clr);
            break;
          case 1:  //A
            //find avg of color components and assign to rgb
            int r = (clr & 0xff0000) >> 16;
            int g = (clr & 0x00ff00) >> 8;
            int b = (clr & 0x0000ff);
            clr = (r + g + b) / 3;
            paint = new Color((clr << 16) | (clr << 8) | (clr));
            break;
          case 2: //R
            paint = new Color(clr & 0xff0000);
            break;
          case 3: //G
            paint = new Color(clr & 0x00ff00);
            break;
          case 4: //B
            paint = new Color(clr & 0x0000ff);
            break;
        }
        break;
      case 1:  //transparent
        if (button1) clr = foreClr; else clr = backClr;
        paint = new Color(clr | (getAlphaLevel() << 24), true);
        break;
      case 2:  //grad (cyclic)
        paint = new GradientPaint(gx[0], gy[0], new Color(foreClr), gx[1], gy[1], new Color(backClr), true);
        break;
      case 3:  //grad (acyclic)
        paint = new GradientPaint(gx[0], gy[0], new Color(foreClr), gx[1], gy[1], new Color(backClr), false);
        break;
      case 4:  //grad (radial - no cycle)
        paint = new RadialGradientPaint(gx[0], gy[0], gradRadius(), gfx, gfy, new float[] {0.0f, 1.0f}, new Color[] {new Color(foreClr), new Color(backClr)}, MultipleGradientPaint.CycleMethod.NO_CYCLE);
        break;
      case 5:  //grad (radial - reflect)
        paint = new RadialGradientPaint(gx[0], gy[0], gradRadius(), gfx, gfy, new float[] {0.0f, 1.0f}, new Color[] {new Color(foreClr), new Color(backClr)}, MultipleGradientPaint.CycleMethod.REFLECT);
        break;
      case 6:  //grad (radial - repeat)
        paint = new RadialGradientPaint(gx[0], gy[0], gradRadius(), gfx, gfy, new float[] {0.0f, 1.0f}, new Color[] {new Color(foreClr), new Color(backClr)}, MultipleGradientPaint.CycleMethod.REPEAT);
        break;
    }
    img.getGraphics2D().setPaint(paint);
  }

  public void swapColors() {
    int tmp = foreClr;
    foreClr = backClr;
    backClr = tmp;
    updateClr(foreColor, foreClr);
    updateClr(backColor, backClr);
  }

  public void changeScale() {
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    int newScale = -1;
    switch (zoom.getValue()) {
      case 0: newScale = 25; break;
      case 1: newScale = 50; break;
      case 2: newScale = 100; break;
      case 3: newScale = 200; break;
      case 4: newScale = 400; break;
      case 5: newScale = 800; break;
    }
    zoomText.setText(Integer.toString(newScale) + "%");
    pc.setScale(newScale);
    pc.parentPanel.revalidate();
    pc.resizeBorder();
    pc.repaint();
  }

  public void actionPerformed(ActionEvent e) {
    //Swing Timer
    repaintTool(imageTabs.get(getidx()).pc);
  }

  public void doPaste(boolean sysClipBoard) {
    int idx = getidx();
    if (idx == -1) return;
    unselectTool(idx);
    selBox.setSelected(true);
    selectTool(tools.selBox);
    Point pt = imageTabs.get(idx).scroll.getViewport().getViewPosition();
    //scale point
    float scale = imageTabs.get(idx).pc.scale / 100f;
    pt.x = (int)(pt.x / scale);
    pt.y = (int)(pt.y / scale);
    pasteSel(pt.x, pt.y, sysClipBoard);
  }

  public boolean dispatchKeyEvent(KeyEvent evt) {
    int id = evt.getID();
    switch (id) {
      case KeyEvent.KEY_TYPED:
        keyTyped(evt);
        break;
      case KeyEvent.KEY_PRESSED:
        keyPressed(evt);
        break;
      case KeyEvent.KEY_RELEASED:
        keyReleased(evt);
        break;
    }
    return false;  //pass on as normal
  }

  public static final int NONE = 0;
  public static final int N = 1;
  public static final int E = 2;
  public static final int S = 3;
  public static final int W = 4;
  public static final int NE = 5;
  public static final int NW = 6;
  public static final int SE = 7;
  public static final int SW = 8;
  public static final int R = 9;
  public static final int INSIDE = 10;
  public static final int OUTSIDE = 11;

  public float rad2deg(float rad) {
    return rad * 180f / (float)Math.PI;
  }

  /** Get selection box point.
   * Adjusts for rotation.
   */
  public int getSelBoxPt(int x,int y) {
    if (!haveSel) return OUTSIDE;
    if (rotate != 0f) {
      GLMatrix mat = new GLMatrix();
      mat.addRotate(rad2deg(rotate), 0, 0, 1);
      GLVector3 vec = new GLVector3();
      vec.v[0] = x - selX1;
      vec.v[1] = y - selY1;
      vec.v[2] = 0;  //z
      mat.mult(vec);
      x = (int)vec.v[0] + selX1;
      y = (int)vec.v[1] + selY1;
    }
    int ox = x - selX1;
    int oy = y - selY1;
    int width = selX2 - selX1 + 1;
    int height = selY2 - selY1 + 1;
    if (x >= selX1 && x <= selX2 && y >= selY1 && y <= selY2) {
      return INSIDE;
    } else {
      if (ox >= width+5 && ox <= width+15 && oy >= height+5 && oy <= height+15) return R;
      if (ox < -5 || ox > width+5) return OUTSIDE;
      if (oy < -5 || oy > height+5) return OUTSIDE;
      int x1 = 0;
      int y1 = 0;
      int x2 = width;
      int y2 = height;
      if (ox >= x2 && oy >= y2) return SE;
      if (ox <= x1 && oy >= y2) return SW;
      if (ox >= x2 && oy <= y1) return NE;
      if (ox <= x1 && oy <= y1) return NW;
      if (oy <= y1) return N;
      if (oy >= y2) return S;
      if (ox <= x1) return W;
      if (ox >= x2) return E;
      return INSIDE;  //should not happen
    }
  }

  public void keyPressed(KeyEvent evt) {
    //Key Pressed
    int f1 = evt.getKeyCode();
    int f2 = evt.getModifiers();
    int idx = getidx();
    if ((f1 == KeyEvent.VK_F1) && (f2 == 0)) {
      JOptionPane.showMessageDialog(this,
        "jfpaint/" + version + "\n\n" +
        "F1 = Help\n" +
        "CTRL-O = Open\n" +
        "CTRL-W = Close\n" +
        "CTRL-S = Save\n" +
        "CTRL-Q = Save As\n" +
        "CTRL-P = Print\n" +
        "CTRL-X = Cut\n" +
        "CTRL-C = Copy\n" +
        "CTRL-V = Paste\n" +
        "CTRL-Z = Undo\n" +
        "CTRL-Y = Redo\n" +
        "ALT-# = Switch to document\n\n"
        , "Help", JOptionPane.INFORMATION_MESSAGE);
      return;
    }
    if ((f1 == KeyEvent.VK_ESCAPE) && (f2 == 0)) { unselectTool(getidx()); return; }
    if ((f1 == KeyEvent.VK_N) && (f2 == KeyEvent.CTRL_MASK)) { addTab("untitled"); return; }
    if ((f1 == KeyEvent.VK_S) && (f2 == KeyEvent.CTRL_MASK)) { saveTab(); return; }
    if ((f1 == KeyEvent.VK_Q) && (f2 == KeyEvent.CTRL_MASK)) { saveAs(); return; }
    if ((f1 == KeyEvent.VK_W) && (f2 == KeyEvent.CTRL_MASK)) { closeTab(false); return; }
    if ((f1 == KeyEvent.VK_O) && (f2 == KeyEvent.CTRL_MASK)) { openTab(); return; }
    if ((f1 == KeyEvent.VK_P) && (f2 == KeyEvent.CTRL_MASK)) { print(); return; }
    if ((f1 == KeyEvent.VK_A) && (f2 == KeyEvent.CTRL_MASK)) { selectAll(); return; }
    if ((f1 == KeyEvent.VK_DELETE) && (f2 == 0)) { delSel(); return; }
    if ((f1 == KeyEvent.VK_Z) && (f2 == KeyEvent.CTRL_MASK)) { undo(); return; }
    if ((f1 == KeyEvent.VK_Y) && (f2 == KeyEvent.CTRL_MASK)) { redo(); return; }
    if ((f2 == KeyEvent.ALT_MASK) && (f1 >= KeyEvent.VK_0) && (f1 <= KeyEvent.VK_9)) {
      idx = f1 - KeyEvent.VK_0;
      if (idx == 0) idx = 9; else idx--;
      if (idx >= imageTabs.size()) return;
      unselectTool(getidx());
      tabs.setSelectedIndex(idx);
      return;
    }
    if ((f2 == KeyEvent.ALT_MASK) && (f1 == KeyEvent.VK_MINUS)) {unselectTool(getidx()); tabs.setSelectedIndex(10);}
    if ((f2 == KeyEvent.ALT_MASK) && (f1 == KeyEvent.VK_EQUALS)) {unselectTool(getidx()); tabs.setSelectedIndex(11);}
  }

  public void keyReleased(KeyEvent e) {}
  public void keyTyped(KeyEvent e) {}

  //the following mouse events are from PaintCanvas, not this Panel

  public void mouseClicked(MouseEvent e) {
    JComponent c = (JComponent)e.getComponent();
    if (c instanceof Border) return;
    PaintCanvas pc = (PaintCanvas)c;
    int x = (int)(e.getX() / (pc.scale / 100f));
    int y = (int)(e.getY() / (pc.scale / 100f));
    if (getGradFocus) {
      gfx = x;
      gfy = y;
      getGradFocus = false;
      updateStatus();
      return;
    }
    pc.disableScale = true;
    pc.setLineWidth(width.getSelectedIndex()+1);
    assignPaint(pc.cimg, e.getButton() == MouseEvent.BUTTON1);
    switch (selectedTool) {
      default:
        pc.disableScale = false;
        return;
      case pencil:
        pc.drawLine(x, y, x, y);
        break;
    }
    pc.disableScale = false;
    pc.setDirty();
    pc.repaint();
  }
  public void mouseEntered(MouseEvent e) {}
  public void mouseExited(MouseEvent e) {}
  public void mousePressed(MouseEvent e) {
    JComponent c = (JComponent)e.getComponent();
    PaintCanvas pc;
    boolean border = false;
    if (c instanceof Border) {
      Border b = (Border)c;
      pc = b.pc;
      border = true;
    } else {
      pc = (PaintCanvas)c;
    }
    pc.grabFocus();
    pc.button = e.getButton();
    int x = (int)(e.getX() / (pc.scale / 100f));
    int y = (int)(e.getY() / (pc.scale / 100f));
    if (border) {
      //start to drag size
      pc.sx = x;
      pc.sy = y;
      pc.createUndo();
      return;
    }
    if (getGradPoints) {
      gx[0] = x;
      gy[0] = y;
      return;
    }
    if (getGradFocus) return;
    pc.disableScale = true;
    pc.setLineWidth(width.getSelectedIndex()+1);
    assignPaint(pc.cimg, e.getButton() == MouseEvent.BUTTON1);
    switch (selectedTool) {
      default:
        pc.disableScale = false;
        return;
      case pencil:
        pc.createUndo();
        pc.sx = x;
        pc.sy = y;
        pc.disableScale = false;
        return;
      case selBox:
      case text:
        int pt = getSelBoxPt(x,y);
        switch (pt) {
          default:
            scretchDir = pt;
            pc.sx = x;
            pc.sy = y;
            break;
          case INSIDE:
            scretchDir = NONE;
            pc.drag = true;
            pc.sx = x;
            pc.sy = y;
            break;
          case OUTSIDE:
            scretchDir = NONE;
            if (pc.drag) {
              if (selectedTool == tools.selBox) drawSel(pc); else drawText(pc);
              pc.drag = false;
              clearSel(pc);
            }
            rotate = 0f;
            selX1 = x;
            selY1 = y;
            haveSel = true;
            if (selectedTool == tools.text) textText = "";
            break;
        }
        //no break
      case line:
      case box:
      case circle:
      case sub:
        pc.createUndo();
        pc.sx = x;
        pc.sy = y;
        pc.disableScale = false;
        return;
      case curve:
        if (cpt == -1) {
          pc.createUndo();
          cpt++;
          cx[cpt] = x;
          cy[cpt] = y;
          cpt++;
        } else {
          mouseDragged(e);
        }
        pc.disableScale = false;
        return;
      case fill:
        int clr = foreClr;
        if (e.getButton() == MouseEvent.BUTTON3) clr = backClr;
        switch (colorLayer.getSelectedIndex()) {
          case 0:  //ARGB
            break;
          case 1:  //A
            //find avg of color components and assign to rgb
            int r = (clr & 0xff0000) >> 16;
            int g = (clr & 0x00ff00) >> 8;
            int b = (clr & 0x0000ff);
            clr = (r + g + b) / 3;
            clr = (clr << 16) | (clr << 8) | (clr);
            break;
          case 2: //R
            clr &= 0xff0000;
            break;
          case 3: //G
            clr &= 0x00ff00;
            break;
          case 4: //B
            clr &= 0x0000ff;
            break;
        }
        pc.createUndo();
        switch (paintMode.getSelectedIndex()) {
          case 0:
            if (fillAlpha.isSelected())
              pc.fillFast(x, y, clr | getAlphaLevel() << 24, true, fillEdge.isSelected(), getThresholdLevel());
            else
              pc.fillFast(x, y, clr, false, fillEdge.isSelected(), getThresholdLevel());
            break;
          default:
            pc.fillSlow(x, y, fillEdge.isSelected(), getThresholdLevel());
            break;
        }
        break;
      case pickColor:
        if (e.getButton() == MouseEvent.BUTTON1) {
          foreClr = pc.img[pc.getImageLayer()].getPixel(x, y);
          updateClr(foreColor, foreClr);
        }
        if (e.getButton() == MouseEvent.BUTTON3) {
          backClr = pc.img[pc.getImageLayer()].getPixel(x, y);
          updateClr(backColor, backClr);
        }
        pc.disableScale = false;
        return;
    }
    pc.disableScale = false;
    pc.setDirty();
    pc.repaint();
  }
  public void mouseReleased(MouseEvent e) {
    JComponent c = (JComponent)e.getComponent();
    if (c instanceof Border) return;
    PaintCanvas pc = (PaintCanvas)c;
    pc.button = -1;
    int tmp;
    int x = (int)(e.getX() / (pc.scale / 100f));
    int y = (int)(e.getY() / (pc.scale / 100f));
    if (getGradPoints) {
      gx[1] = x;
      gy[1] = y;
      pc.foreClear();
      getGradPoints = false;
      if (paintMode.getSelectedIndex() > 3) getGradFocus = true;
      updateStatus();
      pc.repaint();
      return;
    }
    if (getGradFocus) return;
    pc.disableScale = true;
    pc.setLineWidth(width.getSelectedIndex()+1);
    assignPaint(pc.cimg, e.getButton() == MouseEvent.BUTTON1);
    switch (selectedTool) {
      default:
        pc.disableScale = false;
        return;
      case line:
        pc.drawLine(pc.sx, pc.sy, x, y);
        pc.foreClear();
        break;
      case box:
        switch (paintMode.getSelectedIndex()) {
          default:
            if (fillMode.isSelected()) {
              if (round.isSelected())
                pc.fillRoundBox(pc.sx, pc.sy, x, y, arcX, arcY);
              else
                pc.fillBox(pc.sx, pc.sy, x, y);
            } else {
              if (round.isSelected())
                pc.drawRoundBox(pc.sx, pc.sy, x, y, arcX, arcY);
              else
                pc.drawBox(pc.sx, pc.sy, x, y);
            }
            break;
          case 7:
            pc.blur(pc.sx, pc.sy, x, y, filter_radius);
            break;
          case 8:
            pc.pixelate(pc.sx, pc.sy, x, y, filter_pixelSize);
            break;
          case 9:
            pc.chrome(pc.sx, pc.sy, x, y, filter_amount, filter_exposure);
            break;
        }
        pc.foreClear();
        break;
      case circle:
        if (fillMode.isSelected()) {
          pc.fillCircle(pc.sx, pc.sy, x, y);
        } else {
          pc.drawCircle(pc.sx, pc.sy, x, y);
        }
        pc.foreClear();
        break;
      case selBox:
        if (pc.drag) {
          pc.disableScale = false;
          return;
        }
        selX2 = x;
        selY2 = y;
        if ((selX1 == selX2) && (selY1 == selY2)) {haveSel = false; pc.foreClear(); pc.repaint(); return;}
        if (selX1 > selX2) {tmp=selX1; selX1=selX2; selX2=tmp;}
        if (selY1 > selY2) {tmp=selY1; selY1=selY2; selY2=tmp;}
        //copySel();
        cutSel();
        pasteSel(selX1, selY1, false);
        pc.drag = true;
        scretchDir = NONE;
        break;
      case curve:
        cx[cpt] = x;
        cy[cpt] = y;
        cpt++;
        if (cpt != 4) return;
        //draw final curve
        pc.drawCurve(cx, cy);
        cpt = -1;
        break;
      case pencil:
        break;
      case sub:
        switch (paintMode.getSelectedIndex()) {
          case 0:
            pc.subBoxFast(pc.sx, pc.sy, x, y, backClr, foreClr, getThresholdLevel());
            break;
          default:
            pc.subBoxSlow(pc.sx, pc.sy, x, y, backClr, getThresholdLevel());
            break;
        }
        pc.foreClear();
        break;
      case text:
        if (pc.drag) return;
        selX2 = x;
        selY2 = y;
        if ((selX1 == selX2) && (selY1 == selY2)) {haveSel = false; pc.foreClear(); pc.repaint(); return;}
        if (selX1 > selX2) {tmp=selX1; selX1=selX2; selX2=tmp;}
        if (selY1 > selY2) {tmp=selY1; selY1=selY2; selY2=tmp;}
        pc.drag = true;
        break;
    }
    pc.disableScale = false;
    pc.setDirty();
    pc.repaint();
  }
  public void mouseDragged(MouseEvent e) {
    JComponent c = (JComponent)e.getComponent();
    if (c instanceof Border) {
      Border b = (Border)c;
      int x = (int)(e.getX() / (b.pc.scale / 100f));
      int y = (int)(e.getY() / (b.pc.scale / 100f));
      //changing size
      if (b.borderType == Border.Types.east) {
        changeSize(b.pc, x - b.pc.sx, 0, true);
      }
      if (b.borderType == Border.Types.south) {
        changeSize(b.pc, 0, y - b.pc.sy, true);
      }
      if (b.borderType == Border.Types.corner) {
        changeSize(b.pc, x - b.pc.sx, y - b.pc.sy, true);
      }
      imageTabs.get(getidx()).scroll.doLayout();
      doLayout();
      return;
    }
    PaintCanvas pc = (PaintCanvas)c;
    int x = (int)(e.getX() / (pc.scale / 100f));
    int y = (int)(e.getY() / (pc.scale / 100f));
    if (scretchDir != NONE) {
      float width = selX2 - selX1;
      float height = selY2 - selY1;
      switch(scretchDir) {
        case NW:
          selX1 = x;
          selY1 = y;
          break;
        case N:
          selY1 = y;
          break;
        case NE:
          selY1 = y;
          selX2 = x;
          break;
        case E:
          selX2 = x;
          break;
        case SE:
          selX2 = x;
          selY2 = y;
          break;
        case S:
          selY2 = y;
          break;
        case SW:
          selX1 = x;
          selY2 = y;
          break;
        case W:
          selX1 = x;
          break;
        case R:
          rotate = (y - selY2) / height;
          break;
      }
      return;
    }
    pc.disableScale = true;
    if (getGradPoints) {
      pc.foreClear();
      pc.fimg.getGraphics2D().setPaint(new Color(foreClr));
      pc.foreDrawLine(gx[0], gy[0], x, y);
      pc.repaint();
      pc.disableScale = false;
      return;
    }
    if (getGradFocus) {
      pc.disableScale = false;
      return;  //shouldn't happen unless user can't read
    }
    assignPaint(pc.cimg, pc.button == MouseEvent.BUTTON1);
    assignPaint(pc.fimg, pc.button == MouseEvent.BUTTON1);
    switch (selectedTool) {
      case pencil:
        pc.drawLine(pc.sx, pc.sy, x, y);
        pc.sx = x;
        pc.sy = y;
        break;
      case line:
        pc.foreClear();
        pc.foreDrawLine(pc.sx, pc.sy, x, y);
        break;
      case box:
        pc.foreClear();
        if (fillMode.isSelected()) {
          if (round.isSelected())
            pc.foreFillRoundBox(pc.sx, pc.sy, x, y, arcX, arcY);
          else
            pc.foreFillBox(pc.sx, pc.sy, x, y);
        } else {
          if (round.isSelected())
            pc.foreDrawRoundBox(pc.sx, pc.sy, x, y, arcX, arcY);
          else
            pc.foreDrawBox(pc.sx, pc.sy, x, y);
        }
        break;
      case circle:
        pc.foreClear();
        if (fillMode.isSelected()) {
          pc.foreFillCircle(pc.sx, pc.sy, x, y);
        } else {
          pc.foreDrawCircle(pc.sx, pc.sy, x, y);
        }
        break;
      case selBox:
        if (!haveSel) break;
        if (pc.drag) {
          pc.foreClear();
          int dx = (x - pc.sx);
          int dy = (y - pc.sy);
          selX1 += dx;
          selY1 += dy;
          selX2 += dx;
          selY2 += dy;
          foreDrawSel(pc);
          pc.sx = x;
          pc.sy = y;
        } else {
          selX2 = x;
          selY2 = y;
          pc.foreClear();
          pc.foreDrawSelBox(selX1, selY1, selX2, selY2, rotate);
        }
        break;
      case curve:
        cx[cpt] = x;
        cy[cpt] = y;
        pc.foreClear();
        switch (cpt) {
          case 1:
            pc.foreDrawLine(cx[0], cy[0], cx[1], cy[1]);
            break;
          case 2:
            cx[3] = cx[1];
            cy[3] = cy[1];
            //no break
          case 3:
            pc.foreDrawCurve(cx, cy);
            break;
        }
        break;
      case sub:
        pc.foreClear();
        pc.foreDrawBox(pc.sx, pc.sy, x, y);
        break;
      case text:
        if (!haveSel) break;
        if (pc.drag) {
          pc.foreClear();
          int dx = (x - pc.sx);
          int dy = (y - pc.sy);
          selX1 += dx;
          selY1 += dy;
          selX2 += dx;
          selY2 += dy;
          pc.sx = x;
          pc.sy = y;
        } else {
          selX2 = x;
          selY2 = y;
        }
        foreDrawText(pc);
        break;
    }
    pc.disableScale = false;
    updateStatus();
    pc.setDirty();
    pc.repaint();
  }
  public void mouseMoved(MouseEvent e) {
    updateStatus();
  }
  public void keyTypedOnImage(char key) {
    if (selectedTool != tools.text) return;
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    if (key == 8) {
      if (textText.length() > 0) textText = textText.substring(0,textText.length()-1);
    } else if (key == 10) {
      textText += "\n";
    } else {
      textText += key;
    }
    foreDrawText(pc);
    pc.repaint();
  }
  public int getLayer() {
    return colorLayer.getSelectedIndex();
  }
  public void layerChanged() {
    int idx = getidx();
    unselectTool(idx);
    switch (selectedTool) {
      case selBox:
      case sub:
        pencil.doClick();
    }
    PaintCanvas pc = imageTabs.get(idx).pc;
    pc.changeColorLayer(colorLayer.getSelectedIndex());
    if (colorLayer.getSelectedIndex() > 0) {
      paintMode.setSelectedIndex(0);
      paintMode.setEnabled(false);
      selBox.setEnabled(false);
      sub.setEnabled(false);
      thresholdSlider.setEnabled(false);
      rotateCW.setEnabled(false);
      rotateCCW.setEnabled(false);
      flipVert.setEnabled(false);
      flipHorz.setEnabled(false);
      selkeyclr.setEnabled(false);
      fillAlpha.setSelected(false);
      fillAlpha.setEnabled(false);
      fillEdge.setSelected(false);
      fillEdge.setEnabled(false);
    } else {
      int mode = paintMode.getSelectedIndex();
      paintMode.setEnabled(true);
      selBox.setEnabled(true);
      sub.setEnabled(true);
      thresholdSlider.setEnabled(true);
      rotateCW.setEnabled(true);
      rotateCCW.setEnabled(true);
      flipVert.setEnabled(true);
      flipHorz.setEnabled(true);
      selkeyclr.setEnabled(true);
      fillAlpha.setEnabled(mode == 0);
      fillEdge.setEnabled(mode == 0);
    }
    repaint();
    pc.repaint();
  }
  public boolean closeAll() {
    while (tabs.getTabCount() > 0) {
      if (!closeTab(true)) return false;
    }
    return true;
  }
  public void addLayer() {
    int idx = getidx();
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (pc == null) return;
    pc.addImageLayer();
    pc.repaint();
  }
  public void delLayer() {
    int idx = getidx();
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (pc == null) return;
    pc.removeImageLayer(pc.getImageLayer());
    pc.repaint();
  }
  public void editLayer() {
    int idx = getidx();
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (pc == null) return;
    int layer = pc.getImageLayer();
    String newName = JFAWT.getString("Edit layer name", pc.name[layer]);
    if (newName == null) return;
    pc.name[layer] = newName;
  }
  public void dupLayer() {
    int idx = getidx();
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (pc == null) return;
    int layer = pc.getImageLayer();
    int px[] = pc.img[layer].getPixels();
    pc.addImageLayer();
    pc.swapLayers(layer+1, pc.getImageLayers()-1);
    pc.img[layer+1].putPixels(px, 0, 0, pc.getUnscaledWidth(), pc.getUnscaledHeight(), 0);
    pc.repaint();
  }
  public void mergeLayer() {
    int idx = getidx();
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (pc == null) return;
    int layer = pc.getImageLayer();
    if (layer == 0) return;
    pc.img[layer-1].getGraphics().drawImage(pc.img[layer].getImage(), 0, 0, null);
    pc.removeImageLayer(layer);
    pc.setImageLayer(layer-1);
    pc.repaint();
  }
  public void moveLayerUp() {
    int idx = getidx();
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (pc == null) return;
    int layer = pc.getImageLayer();
    if (layer == 0) return;
    pc.swapLayers(layer, layer-1);
    pc.setImageLayer(layer-1);
    pc.repaint();
  }
  public void moveLayerDown() {
    int idx = getidx();
    if (idx == -1) return;
    PaintCanvas pc = imageTabs.get(idx).pc;
    if (pc == null) return;
    int layer = pc.getImageLayer();
    if (layer == pc.getImageLayers()-1) return;
    pc.swapLayers(layer, layer+1);
    pc.setImageLayer(layer+1);
    pc.repaint();
  }
  public void crop() {
    if (!haveSel) return;
    PaintCanvas pc = imageTabs.get(getidx()).pc;
    int ox = pc.getUnscaledWidth();
    int oy = pc.getUnscaledHeight();
    int sx = selX2 - selX1 + 1;
    int sy = selY2 - selY1 + 1;
    changeSize(pc, sx - ox, sy - oy, false);
    pc.img[pc.getImageLayer()].fill(0, 0, sx, sy, backClr, true);
    pasteSel(0, 0, false);
    unselectTool(getidx());
  }
}
